/**
 *  Copyright (C) 2010:
 *                 Buzzanca Marco <marco.bzn@gmail.com>
 *         Monaco Davide Giuseppe <black.ralkass@gmail.com>
 *              Petralia Veronica <veronicapetralia@gmail.com>
 *
 * This file is part of DS2011BMP
 *
 * DS2011BMP is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * DS2011BMP is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

/**
 * @file workerdiscovery.h
 * @author Marco Buzzanca
 *
 * This file contains WorkerDiscovery class declaration.
 */

#ifndef _WORKER_DISCOVERY_H_
#define _WORKER_DISCOVERY_H_ 1

#include <boost/cstdint.hpp>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <vector>

#include "address.h"
#include "udpserver.h"
#include "workerdescriptor.h"
#include "taskdescriptor.h"
#include "worker.h"

/**
 * WorkerDiscovery
 *
 * Provides local access to workers list for discovery node. It also hosts a
 * a server for manager node, providing a suitable worker, and a server for
 * workers node, providing subscription services.
 */
class WorkerDiscovery
{
private:
    /**
     * Collection typedefs.
     */
    typedef std::vector<WorkerDescriptor>   collection;
    typedef collection::size_type           collection_size_t;

    /**
     * @brief Workers collection.
     */
    collection _workers;

    /**
     * @brief Collection-guarding mutex.
     */
    boost::mutex _mutex;

    /**
     * @brief It will behave as a server, so we need an UDPServer object.
     */
    UDPServer _server;

    /**
     * @brief WorkerDiscovery thread called by server thread
     *        callback member function, used to process a request.
     */
    void serve(UDPServer::Responder responder);

public:
    /**
     * @brief Constructor. Default port value is 13000.
     */
    WorkerDiscovery(boost::uint16_t port = 13000)
      : _server(port) { }

    /**
     * @brief Constructor specifying address object.
     * @param address Server address.
     */
    WorkerDiscovery(const Address& address)
      : _server(address) { }

    /**
     * @brief Destructor.
     */
    ~WorkerDiscovery(void) { }

    /**
     * @brief Listens for UDP packets and create a new servant
     *        for the request.
     */
    void run(void);

    /**
     * @brief Returns the address of a worker capable of handling provided
     *        TaskDescriptor.
     *
     * @param td The provided TaskDescriptor.
     * @return The Address of a Worker capable to handle provided TaskDescriptor.
     */
    Address getWorker(const TaskDescriptor& td);

    /**
     * @brief Repleces WorkerDescriptor object at provided index with the 
     *        provided one.
     *
     * @param index The provided position in the collection.
     * @param wd The new WorkerDescriptor that will replace the old one.
     */
    void updateWorker(size_t index, const WorkerDescriptor& wd);

    /**
     * @brief Adds provided WorkerDescriptor object into the container of workers.
     * @param wd  The provided WorkerDescriptor.
     */
    void addWorker(const WorkerDescriptor& wd);

    /**
     * @brief Removes the WorkerDescriptor object at the provided position from 
     *        the container of workers
     *
     * @param index The provided position.
     */
    void removeWorker(size_t index);

    /**
     * @brief Erases the container of workers.
     */
    void clear(void);

    /**
     * @brief Returns the number of registered workers.
     * @return The number of workers (which is actually the container size).
     */
    collection_size_t size(void);

    /**
     * @brief Checks whenever the container of workers is empty.
     * @return true if the container is empty, otherwise false.
     */
    bool empty(void);

    /**
     * @brief Gets server port.
     * @return Server port.
     */
    boost::uint16_t getPort(void) const;

    /**
     * @brief Sets server port.
     * @param port The provided port.
     */
    void setPort(boost::uint16_t port);

    /**
     * @brief Sets server port using provided Address.
     * @param address Server address.
     */
    void setPort(const Address& address);

};

#endif /* _WORKER_DISCOVERY_H_ */
